package org.example.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.mongodb.client.model.Field;
import org.example.dao.GroupRepository;
import org.example.dao.UserGroupRepository;
import org.example.dao.UserRepository;
import org.example.enums.RoomRoleEnum;
import org.example.packets.LastMessage;
import org.example.packets.bean.Group;
import org.example.packets.bean.User;
import org.example.packets.bean.UserGroup;
import org.example.packets.handler.user.GroupUser;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.mongodb.client.model.Aggregates.set;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Updates.combine;

public class UserGroupService {

    private final UserGroupRepository userGroupRepository;

    private final UserRepository userRepository;
    private final GroupRepository groupRepository;

    public UserGroupService() {
        userRepository = new UserRepository();
        userGroupRepository = new UserGroupRepository();
        groupRepository = new GroupRepository();
    }

    public void addGroupUser(String roomId, String userId) {
        addGroupUser(roomId, userId, RoomRoleEnum.GENERAL, false);
    }

    public void addGroupUser(String roomId, String userId, RoomRoleEnum role, Boolean isFriend) {
        UserGroup userGroup = new UserGroup();
        userGroup.setUserId(userId);
        userGroup.setRoomId(roomId);
        userGroup.setNotice(true);
        userGroup.setRole(role);
        userGroup.setIsFriend(isFriend);
        userGroupRepository.saveOrUpdate(and(eq("userId", userId), eq("roomId", roomId)), userGroup);
    }

    public List<UserGroup> getGroupUsers(String roomId) {
        return userGroupRepository.find(eq("roomId", roomId));
    }

    public List<Group> getUserGroups(String userId) {
        List<UserGroup> userGroups = userGroupRepository.find(and(eq("userId", userId), ne("roomDeleted", true)));
        List<String> groupIds = userGroups.stream().map(UserGroup::getRoomId).collect(Collectors.toList());

        List<UserGroup> userGroupList = userGroupRepository.find(and(in("roomId", groupIds)));
        Map<String, List<UserGroup>> collect = userGroupList.stream().collect(Collectors.groupingBy(UserGroup::getRoomId));

        List<Group> groupList = new ArrayList<>();
        collect.forEach((k, v) -> {
            groupList.add(this.getUserGroup(k, userId, v));
        });

        return groupList.stream().sorted(Comparator.comparing(Group::getIndex).reversed()).collect(Collectors.toList());
    }

    public Group getUserGroup(String groupId, String userId, List<UserGroup> userGroups) {
        if (CollUtil.isEmpty(userGroups)) {
            userGroups = userGroupRepository.find(eq("roomId", groupId));
        }
        Group group = groupRepository.findById(groupId);
        group.setUsers(new ArrayList<>());
        for (UserGroup userGroup : userGroups) {
            if (userGroup.getUserId().equals(userId)) {
                group.setNotice(userGroup.getNotice());
                group.setRoomName(StrUtil.isNotBlank(userGroup.getRemark()) ? userGroup.getRemark() : group.getRoomName());
                group.setIndex(Boolean.TRUE.equals(userGroup.getTop()) ? 9999999999999L : group.getIndex());
                group.setBlack(userGroup.getBlack());
            }
            GroupUser groupUser = new GroupUser()
                    .setId(userGroup.getUserId())
                    .setRole(userGroup.getRole())
                    .setBlack(userGroup.getBlack());
            group.getUsers().add(groupUser);
        }
        return group;
    }

    public void remove(String roomId, String userId) {
        userGroupRepository.delete(and(eq("roomId", roomId), eq("userId", userId)));
    }

    public UserGroup getUserGroup(String roomId, String userId) {
        return userGroupRepository.findOne(and(eq("roomId", roomId), eq("userId", userId)));
    }

    public void update(UserGroup userGroup) {
        userGroupRepository.replace(and(eq("roomId", userGroup.getRoomId()), eq("userId", userGroup.getUserId())), userGroup);
    }

    public void delete(String roomId) {
        userGroupRepository.updateMany(eq("roomId", roomId), set(new Field<>("roomDeleted", true)));
    }
}
